// RegistryPlugins.cpp

#include "StdAfx.h"

#include "Common/System/DLL.h"
#include "Common/MS/PropVariant.h"
#include "Common/FileSystem/FileFind.h"

#include "Common/App/ProgramLocation.h"
#include "RegistryPlugins.h"
#include "Common/FileSystem/IFolder.h"


using namespace Common;
using namespace System;
using namespace FileSystem;

namespace Common
{
namespace Registry
{

/*
static const TCHAR *kLMBasePath = TEXT("Software\\7-Zip\\FM");

static const TCHAR *kPluginsKeyName = TEXT("Plugins");
static const TCHAR *kPluginsOpenClassIDValue = TEXT("CLSID");
static const TCHAR *kPluginsOptionsClassIDValue = TEXT("Options");
static const TCHAR *kPluginsTypeValue = TEXT("Type");

static CString GetFileFolderPluginsKeyName()
{
  return CString(kLMBasePath) + CString(TEXT('\\')) +
      CString(kPluginsKeyName);
}

*/

typedef UINT32 (WINAPI* GetPluginPropertyFunc)(PROPID propID, PROPVARIANT* value);

static bool ReadPluginInfo(CPluginInfo* pluginInfo, bool needCheckDll)
{
	ATLASSERT(NULL != pluginInfo);
	if (needCheckDll)
	{
		DLL::CLibrary lib;
		if (!lib.LoadEx(pluginInfo->FilePath, LOAD_LIBRARY_AS_DATAFILE))
		{
			return false;
		}
	}
	DLL::CLibrary lib;
	if (!lib.Load(pluginInfo->FilePath))
	{
		return false;
	}
	GetPluginPropertyFunc getPluginProperty = (GetPluginPropertyFunc)lib.GetProcAddress("GetPluginProperty");
	if (getPluginProperty == NULL)
	{
		return false;
	}

	CComPropVariant prop;
	if (getPluginProperty(static_cast<PROPID>(Plugin::kName), &prop) != S_OK)
	{
		return false;
	}
	if (prop.vt != VT_BSTR)
	{
		return false;
	}
	pluginInfo->Name = prop.bstrVal;
	prop.Clear();

	if (getPluginProperty(static_cast<PROPID>(Plugin::kClassID), &prop) != S_OK)
	{
		return false;
	}
	if (prop.vt == VT_EMPTY)
	{
		pluginInfo->ClassIDDefined = false;
	}
	else if (prop.vt != VT_BSTR)
	{
		return false;
	}
	else
	{
		pluginInfo->ClassIDDefined = true;
		pluginInfo->ClassID = *(const GUID*)prop.bstrVal;
	}
	prop.Clear();

	if (getPluginProperty(static_cast<PROPID>(Plugin::kOptionsClassID), &prop) != S_OK)
	{
		return false;
	}
	if (prop.vt == VT_EMPTY)
	{
		pluginInfo->OptionsClassIDDefined = false;
	}
	else if (prop.vt != VT_BSTR)
	{
		return false;
	}
	else
	{
		pluginInfo->OptionsClassIDDefined = true;
		pluginInfo->OptionsClassID = *(const GUID*)prop.bstrVal;
	}
	prop.Clear();

	if (getPluginProperty(static_cast<PROPID>(Plugin::kType), &prop) != S_OK)
	{
		return false;
	}
	if (prop.vt == VT_EMPTY)
	{
		pluginInfo->Type = kPluginTypeFF;
	}
	else if (prop.vt == VT_UI4)
	{
		pluginInfo->Type = (EPluginType)prop.ulVal;
	}
	else
	{
		return false;
	}
	return true;
}

CString GetProgramFolderPrefix();

void ReadPluginInfoList(std::vector<std::shared_ptr<CPluginInfo> >  &plugins)
{
	plugins.clear();

	CString baseFolderPrefix;
	App::GetProgramFolderPath(baseFolderPrefix);
	{
		std::shared_ptr<CPluginInfo> pluginInfo = std::make_shared<CPluginInfo>();
		pluginInfo->FilePath = baseFolderPrefix + _T("7-zip.dll");
		if (Registry::ReadPluginInfo(pluginInfo.get(), false))
		{
			plugins.push_back(pluginInfo);
		}
	}
	CString folderPath = baseFolderPrefix + _T("Plugins") STRING_PATH_SEPARATOR;
	Find::CEnumerator enumerator(folderPath + _T("*"));
	File::CFileInfo fileInfo;
	while (enumerator.Next(&fileInfo))
	{
		if (fileInfo.IsDir())
		{
			continue;
		}
		std::shared_ptr<CPluginInfo> pluginInfo = std::make_shared<CPluginInfo>();
		pluginInfo->FilePath = folderPath + fileInfo.Name;
		if (Registry::ReadPluginInfo(pluginInfo.get(), true))
		{
			plugins.push_back(pluginInfo);
		}
	}
}

void ReadFileFolderPluginInfoList(std::vector<std::shared_ptr<CPluginInfo> >  &plugins)
{
	ReadPluginInfoList(plugins);
	for (size_t i = 0; i < plugins.size();)
		if (plugins[i]->Type != kPluginTypeFF)
		{
			plugins.erase(plugins.begin() + i);
		}
		else
		{
			i++;
		}
	{
		std::shared_ptr<CPluginInfo> p = std::make_shared<CPluginInfo>();
		// p.FilePath.Empty();
		p->Type = kPluginTypeFF;
		p->Name = _T("7-Zip");
		// p.ClassID = CLSID_CAgentArchiveHandler;
		p->ClassIDDefined = true;
		// p.OptionsClassID;
		p->OptionsClassIDDefined = false;
		plugins.push_back(p);
	}
}

} //namespace Registry

} //namespace Common